package org.jaronsource.framework.core.dao.support;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;

public class GenericDao<T extends IEntity<I>, I extends Serializable> implements IGenericDao<T, I> {

	protected Log log = LogFactory.getLog( getClass() );

	@Autowired
	protected ICommonDao commonDao;

	private Class<T> clazz;

	@SuppressWarnings ( value = "unchecked")
	public GenericDao() {

		Type[] types = ( (ParameterizedType) getClass().getGenericSuperclass() ).getActualTypeArguments();

		if ( types[0] instanceof ParameterizedType ) {
			ParameterizedType type = (ParameterizedType) types[0];
			clazz = (Class<T>) type.getRawType();
		}
		else {
			clazz = (Class<T>) types[0];
		}
	}

	public GenericDao(	Class<T> clazz ) {
		this.clazz = clazz;
	}

	public EntityManager getEntityManager() {
		return commonDao.getEntityManager();
	}

	@Override
	public T save( T target ) {
		return commonDao.save( target );
	}

	public void flush() {
		commonDao.getEntityManager().flush();
	}

	@Override
	public T[] save( T... targets ) {
		return commonDao.save( targets );
	}
	
	@Override
	public void update( T target, I pk ) {
		commonDao.update( target, pk );
	}

	@Override
	public void remove( T target ) {
		commonDao.remove( target );
	}

	@Override
	public void remove( T... targets ) {
		commonDao.remove( targets );
	}

	@Override
	public void remove( I id ) {
		commonDao.remove( clazz, id );
	}
	
	@Override
	public void remove( I... ids ) {
		commonDao.remove( clazz, ids );
	}

	@Override
	public boolean exists( I id ) {
		return commonDao.exists( clazz, id );
	}

	@Override
	public T findByPk( I id ) {
		return commonDao.findByPk( clazz, id );
	}

	@Override
	public T findReferenceByPk( I id ) {
		return commonDao.findReferenceByPk( clazz, id );
	}

	@Override
	public T findOne( Criteria criteria ) {
		return commonDao.findOne( clazz, criteria );
	}

	@Override
	public T findOne( String jpql, Object... params ) {
		return commonDao.findOne( clazz, jpql, params );
	}

	@Override
	public T findOne( String jpql, Map<String, ?> params ) {
		return commonDao.findOne( clazz, jpql, params );
	}

	@Override
	public List<T> findAll() {
		return commonDao.findAll( clazz );
	}

	@Override
	public List<T> find( Criteria criteria ) {
		return commonDao.find( clazz, criteria );
	}

	@Override
	public List<T> find( String jpql, Object... params ) {
		return commonDao.find( clazz, jpql, params );
	}

	@Override
	public List<T> find( String jpql, Map<String, ?> params ) {
		return commonDao.find( clazz, jpql, params );
	}

	@Override
	public long count( Criteria criteria ) {
		return commonDao.count( clazz, criteria );
	}

	@Override
	public long count( String jpql, Object... params ) {
		return commonDao.count( jpql, params );
	}

	@Override
	public long count( String jpql, Map<String, ?> params ) {
		return commonDao.count( jpql, params );
	}

	@Override
	public List<T> find( Sort sort, Criteria criteria ) {
		return commonDao.find( clazz, sort, criteria );
	}

	@Override
	public List<T> find( PageRequest pageRequest, Criteria criteria ) {
		return commonDao.find( clazz, pageRequest, criteria );
	}

	@Override
	public List<T> find( Sort sort, String jpql, Object... params ) {
		return commonDao.find( clazz, sort, jpql, params );
	}

	@Override
	public List<T> find( Sort sort, String jpql, Map<String, ?> params ) {
		return commonDao.find( clazz, sort, jpql, params );
	}

	@Override
	public List<T> find( PageRequest pageRequest, String jpql, Object... params ) {
		return commonDao.find( clazz, pageRequest, jpql, params );
	}

	@Override
	public List<T> find(	PageRequest pageRequest,
							String jpql,
							Map<String, ?> params ) {
		return commonDao.find( clazz, pageRequest, jpql, params );
	}

	@Override
	public Page<T> findPage( PageRequest pageRequest, Criteria criteria ) {
		return commonDao.findPage( clazz, pageRequest, criteria );
	}

	@Override
	public Page<T> findPage(	PageRequest pageRequest,
								String jpql,
								Object... params ) {
		return commonDao.findPage( clazz, pageRequest, jpql, params );
	}

	@Override
	public Page<T> findPage(	PageRequest pageRequest,
								String jpql,
								Map<String, ?> params ) {
		return commonDao.findPage( clazz, pageRequest, jpql, params );
	}

	@Override
	public T findOne( Sort sort, Criteria criteria ) {
		return commonDao.findOne( clazz, sort, criteria );
	}

	@Override
	public T findOne( Sort sort, String jpql, Object... params ) {
		return commonDao.findOne( clazz, sort, jpql, params );
	}

	@Override
	public T findOne( Sort sort, String jpql, Map<String, ?> params ) {
		return commonDao.findOne( clazz, sort, jpql, params );
	}

}